﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NeuralStock.DomainService.Interfaces;
using NeuralStock.Entities;
using System.IO;
using NeuralStock.Common;

namespace NeuralStock.DomainService.Implementation
{
    public class CapEbitService : BaseService, ICapEbitService
    {
        private const int analyzedReportsYearSpan = 5;

        private readonly ICompanyService companyService;
        private readonly IFinancialReportService financialReportService;
        private readonly ICompanyQuotationService companyQuotationService;

        public CapEbitService(ICompanyService companyService, IFinancialReportService financialReportService, ICompanyQuotationService companyQuotationService)
        {
            this.companyService = companyService;
            this.financialReportService = financialReportService;
            this.companyQuotationService = companyQuotationService;
        }

        public CapEbitCompanyResult CalculateCapEbit(int companyId, int lastReportYear, int firstYearOfInvestment, bool isHistorical)
        {
            CapEbitCompanyResult result = new CapEbitCompanyResult();

            var financialReports = financialReportService.GetFinancialReportsForCapEbit(companyId, lastReportYear, analyzedReportsYearSpan);

            var baseData = financialReports
                .Select(x => new
                {
                    x.Year,
                    x.NumberOfShares,
                    Ebit = x.ProfitFromOperatingActivities,
                    MinPrice = companyQuotationService.GetMinPriceForYear(companyId, x.Year),
                    AvgPrice = companyQuotationService.GetAvgPriceForYear(companyId, x.Year)
                })
                .OrderBy(x => x.Year)
                .ToList();

            var capEbitdas = baseData
                .Skip(1)
                .Where(x => baseData.Single(y => y.Year == x.Year - 1).Ebit > 0)
                .Select(x => new
                {
                    CapEbitdaByMinPrice = (x.NumberOfShares * x.MinPrice) / (baseData.Single(y => y.Year == x.Year - 1).Ebit),
                })
                .OrderByDescending(x => x.CapEbitdaByMinPrice)
                .Skip(1)
                .ToList();

            if (capEbitdas.Count() < 4)
            {
                throw new InvalidDataException("Less than 4 reports analyzed");
            }

            result.YearsAnalyzed = capEbitdas.Count();

            result.AvgCapEbitdaMinPrice = capEbitdas.Average(x => x.CapEbitdaByMinPrice).Value;

            decimal currentPrice;
            decimal currentNumberOfShares;
            decimal lastEbitda = baseData.Last().Ebit.Value;

            if (lastEbitda < 0)
            {
                throw new InvalidOperationException("LastEbitda < 0");
            }

            if (!isHistorical)
            {
                currentPrice = companyQuotationService.GetLastPrice(companyId);
                currentNumberOfShares = companyService.Get(companyId).CurrentNumberOfShares.Value;
            }
            else
            {
                currentPrice = companyQuotationService.GetQuoteAfterFirstQuarter(companyId, firstYearOfInvestment).Price;
                currentNumberOfShares = financialReportService.Get(companyId, firstYearOfInvestment).NumberOfShares.Value;
            }

            decimal currentCapEbitda = (currentPrice * currentNumberOfShares) / (lastEbitda);
            result.CurrentCapEbitda = currentCapEbitda;

            result.PotentialGrowthByMinPrice = (result.AvgCapEbitdaMinPrice / currentCapEbitda - 1);

            decimal grahamSecurityBuffer = 0.5m;
            result.PotentialGrowthByMinPriceSafe = grahamSecurityBuffer * (result.AvgCapEbitdaMinPrice / currentCapEbitda - 1);

            return result;
        } 
    }
}
